﻿using CommunityToolkit.Mvvm.ComponentModel;
using DataCollection.Core.Models;
using DataCollection.Infrastructure;
using Mapster;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.VisualBasic.Logging;
using Modbus.Device;
using SqlSugar;
using System;
using System.IO.Ports;
using System.Reflection;

namespace DataCollection.WinForm.ViewModel
{
    public delegate void ReadRegisterError(string msg, Exception ex);

    public delegate void PointValueError(string msg);

    internal partial class CollectionViewModel : ObservableObject
    {
        #region 属性

       public event ReadRegisterError? ReadRegisterErrorEvent;

        public event PointValueError? PointValueErrorEvent;

        /// <summary>
        /// 串口字典 【设备编号->SerialPort】
        /// </summary>
        public Dictionary<string, SerialPort> DeviceSerialPortDic = new Dictionary<string, SerialPort> { };

        /// <summary>
        /// 点位字典 【点位编号->DevicePointModel】
        /// </summary>
        private Dictionary<string, DevicePointModel> DevicePointDic = new Dictionary<string, DevicePointModel> { };

        /// <summary>
        /// 需要采集的点位
        /// </summary>
        public List<CollectionModel> CollectionList = new List<CollectionModel>();

        /// <summary>
        /// 界面点位列表
        /// </summary>
        public List<FormPointModel> FormPointList = new List<FormPointModel>();

        #endregion


        public void Setup()
        {
            LoadDeviceList();
        }

        /// <summary>设备列表
        /// 
        /// </summary>
        public void LoadDeviceList()
        {
            //Dictionary<string, Object> where = new Dictionary<string, Object>();
            List<DeviceModel> list = DeviceModel.PointList();
            foreach (DeviceModel item in list)
            {
                if (item.Enable == "停用")
                {
                    Log.Info(string.Format("【{0}】停用", item.Name));
                    return;
                }
                string deviceNumber = item.Number.ToString();
                string port_address = item.PortAddress; // 串口地址
                int baudRate = (int)item.Baudrate;   // 波特率
                var dataBits = 8;      // 数据位
                var stopBits = StopBits.One; // 停止位
                var parity = Parity.None;    // 校验位
                SerialPort serialPort = new SerialPort(port_address, baudRate, parity, dataBits, stopBits);
                Log.Debug(string.Format("【{0}】开始联接", port_address));
                try
                {
                    serialPort.Open();
                    if (serialPort.IsOpen)
                    {
                        Log.Info(string.Format("【{0}】连接成功✔", port_address));
                        string key = item.Number.ToString();
                        CollectionModel model = new CollectionModel();
                        if (item.HoldingRegisterCount > 0)
                        {
                            model = new CollectionModel();
                            item.Adapt(model);
                            model.serialPort = serialPort;
                            model.RCount = item.HoldingRegisterCount;
                            model.RegisterType = "HR";
                            LoadDevicePointList(model);
                            if (model.PointList.Count > 0)
                            {
                                CollectionList.Add(model);
                            }
                        }

                        if (item.InputRegisterCount > 0)
                        {
                            model = new CollectionModel();
                            item.Adapt(model);
                            model.serialPort = serialPort;
                            model.RCount = item.InputRegisterCount;
                            model.RegisterType = "IR";
                            LoadDevicePointList(model);
                            if (model.PointList.Count > 0)
                            {
                                CollectionList.Add(model);
                            }
                        }

                        if (item.InputStatusCount > 0)
                        {
                            model = new CollectionModel();
                            item.Adapt(model);
                            model.serialPort = serialPort;
                            model.RCount = item.InputStatusCount;
                            model.RegisterType = "DI";
                            LoadDevicePointList(model);
                            if (model.PointList.Count > 0)
                            {
                                CollectionList.Add(model);
                            }
                        }

                        if (item.CoilStatusCount > 0)
                        {
                            model = new CollectionModel();
                            item.Adapt(model);
                            model.serialPort = serialPort;
                            model.RegisterType = "DO";
                            model.RCount = item.CoilStatusCount;
                            LoadDevicePointList(model);
                            if (model.PointList.Count > 0)
                            {
                                CollectionList.Add(model);
                            }
                        }
                    }
                    else
                    {
                        Log.Error(string.Format("【{0}】连接失败❌", port_address));
                    }
                    LoadFormPointList();
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("【{0}】连接异常【{1}】❌", port_address, ex.Message));
                }
            }
            Log.Debug("111");
        }

        /// <summary>界面点位列表
        /// 
        /// </summary>
        public void LoadDevicePointList(CollectionModel model)
        {
            Dictionary<string, Object> where = new Dictionary<string, Object>();
            where["point_type"] = model.RegisterType;
            where["device_number"] = model.Number;
            List<DevicePointModel> list = DevicePointModel.List(where);
            if (list.Count <= 0)
            {
                Log.Info(string.Format("【{0}--{1}】点位为0",model.Name,model.RegisterType));
            }
            model.PointList = list;
        }

        /// <summary>
        /// 界面点位列表
        /// </summary>
        public void LoadFormPointList()
        {
            Dictionary<string, Object> where = new Dictionary<string, Object>();
            where["enable"] = 0;
            List<FormPointModel> list = FormPointModel.List(where);
            foreach (FormPointModel item in list)
            {
                Log.Info(string.Format("界面点位【{0}】停用", item.Name));
            }
        }

        public double Invoke(string method, DevicePointModel item, ushort value)
        {
            Type type = typeof(CollectionViewModel);
            MethodInfo? mt = type.GetMethod(method, BindingFlags.NonPublic | BindingFlags.Instance);
            if (mt is not null)
            {
                object? obj = mt.Invoke(this, [item, value]);
                if (obj != null)
                {
                   double res = (double)obj;
                    res = res > 0 ? res : 0;
                   return res; 
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;   
            }
        }

        /// <summary>
        /// 读取ushort
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public ushort[]? ReadUShort(CollectionModel item)
        {
            ushort count = ushort.Parse(item.RCount.ToString());
            if (item.serialMaster is not null)
            {
                ModbusSerialMaster master = item.serialMaster;
                byte slaveAddress = (byte)int.Parse(item.SlaveAddress);
                Task<ushort[]>? ushortTask = master.ReadHoldingRegistersAsync(slaveAddress, 0, count);
                try
                {
                    ushort[] shorts = ushortTask.Result;
                    return shorts;
                }
                catch (Exception ex)
                {
                    string msg = string.Format(" 【{0}】读取异常", item.Name);
                    if (ReadRegisterErrorEvent is not null)
                    {
                        ReadRegisterErrorEvent(msg,ex);
                    }
                    Log.Error(string.Format(" {0}：{1}❌", msg, ex.Message));
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 读取ushort
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool[]? ReadBool(CollectionModel item)
        {
            ushort count = ushort.Parse(item.RCount.ToString());
            if (item.serialMaster is not null)
            {
                ModbusSerialMaster master = item.serialMaster;
                byte slaveAddress = (byte)int.Parse(item.SlaveAddress);
                Task<bool[]> boolTask;
                if (item.RegisterType == "DI")
                {
                    boolTask = master.ReadInputsAsync(slaveAddress, 0, count);
                }
                else
                {
                    boolTask = master.ReadCoilsAsync(slaveAddress, 0, count);
                }
                try
                {
                    bool[] shorts = boolTask.Result;
                    return shorts;
                }
                catch (Exception ex)
                {
                    string msg = string.Format(" 【{0}】读取异常", item.Name);
                    if (ReadRegisterErrorEvent is not null)
                    {

                        ReadRegisterErrorEvent(msg, ex);
                    }
                    Log.Error(string.Format(" {0}：{1}❌", msg, ex.Message));
                    return null;
                }
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// 转换
        /// </summary>
        /// <param name="model"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private double Parse(DevicePointModel model, double value)
        {
            string log = string.Empty;
            double temperature = value;
            double backTemperature = Math.Round(temperature, 3);
            double TemperatureScaleMultiple = Singleton.Instance.SetModel.TemperatureScaleMultiple;
            if (TemperatureScaleMultiple > 0)
            {
                backTemperature = backTemperature / TemperatureScaleMultiple;
            }
            log = string.Format("【{0}:{1}】", model.Name, backTemperature);
            //Log.Debug(log);
            return backTemperature;
        }

        /// <summary>
        /// 转换量程
        /// </summary>
        /// <param name="model"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private double ParseRange(DevicePointModel model, double value)
        {
            string log = string.Empty;
            double pressureTmp = value;
            double outMax = model.OutMax;
            double outMin = model.OutMin;
            double rangeMax = model.RangeMax;
            double rangeMin = model.RangeMin;
            if (Singleton.Instance.SetModel.PressureScaleMultiple > 0)
            {
                pressureTmp = (double)(value / Singleton.Instance.SetModel.PressureScaleMultiple);
            }

            if (pressureTmp < model.OutMin)
            {
                string msg = string.Format("【{0}】采集值【{1}】低于最小输出值【{2}】", model.Name, pressureTmp, model.OutMin);
                Log.Error(msg);
                if (PointValueErrorEvent is not null)
                {
                    PointValueErrorEvent(msg);
                }
                return -999;
            }
            if (pressureTmp > model.OutMax)
            {
                string msg = string.Format("【{0}】采集值【{1}】高于最大输出值【{2}】", model.Name, pressureTmp, model.OutMax);
                Log.Error(msg);
                if (PointValueErrorEvent is not null)
                {
                    PointValueErrorEvent(msg);
                }
                return -999;
            }
            double pressure = (pressureTmp - outMin) / (outMax - outMin);
            pressure = Math.Round(pressure * (rangeMax - rangeMin) + rangeMin, 3);
            if (model.Amend > 0)
            {
                pressure = Math.Round(pressure * model.Amend, 3);
            }

            log = string.Format("【{0}:{1}】", model.Name, pressure);
           // Log.Debug(log);

            return pressure;
        }

        /// <summary>
        /// 转换
        /// </summary>
        /// <param name="model"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private double Custome(DevicePointModel model, double value)
        {
            string log = string.Empty;
            double temperature = value;
            double backTemperature = Math.Round(temperature, 3);
            double TemperatureScaleMultiple = Singleton.Instance.SetModel.TemperatureScaleMultiple;
            if (TemperatureScaleMultiple > 0)
            {
                backTemperature = (backTemperature / TemperatureScaleMultiple ) - 30;
            }
            log = string.Format("【{0}:{1}】", model.Name, backTemperature);
            //Log.Debug(log);
            return backTemperature;
        }
    }

    internal class CollectionModel
    {
        public string Number = null!;

        public string Name = null!;

        public string SlaveAddress = null!;

        public string RegisterType = null!;

        public int RCount = 0;

        public int PointCount
        {
            get 
            {
                if (PointList is not null)
                {
                    return PointList.Count;
                }
                else
                {
                    return 0;
                }
            }
        }

        public SerialPort? serialPort;

        public ModbusSerialMaster? serialMaster 
        {
            get {

                if (serialPort is not null)
                {
                    return ModbusSerialMaster.CreateRtu(serialPort);
                }
                else
                {
                    return null;
                }
            }
        }

        public List<DevicePointModel> PointList = new List<DevicePointModel>();

    }

    internal class Params
    {
        public DevicePointModel model = null!;

        public double value;
    }
}
